package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.article.ArticleConstants;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.constants.message.WmNewsMessageConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.file.config.OssAliyunConfigProperties;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.NewsAuthDto;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vos.NewsAuthVo;
import com.heima.utils.threadlocal.WmThreadLocalUtils;
import com.heima.wemedia.mapper.*;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 自媒体图文内容信息表 服务实现类
 * </p>
 *
 * @author itheima
 */
@Slf4j
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Value("${file.oss.web-site}")
    private String webSite;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    ArticleFeign articleFeign;

    /**
     * 条件分页查询
     * 展示文章列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByPage(WmNewsPageDto dto) {
        //参数校验
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
        //设置查询条件
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery();
        //标题模糊查询关键词
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            wrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        //文章状态查询
        if (dto.getStatus() != null) {
            wrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        //频道列表查询
        if (dto.getChannelId() != null) {
            wrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        //发布时间查询
        if (dto.getBeginPubdate() != null && dto.getEndPubdate() != null) {
            wrapper.between(WmNews::getPublishTime, dto.getBeginPubdate(), dto.getEndPubdate());
        }
        //必须要是本人账号
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        wrapper.eq(WmNews::getUserId, user.getId());
        //根据创建时间降序排序
        wrapper.orderByDesc(WmNews::getCreatedTime);
        //执行分页查询
        IPage<WmNews> pages = page(new Page<WmNews>(dto.getPage(), dto.getSize()), wrapper);
        //条件封装返回
        ResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), pages.getTotal(), pages.getRecords());
        //返回结果添加图片访问前缀
        result.setHost(webSite);
        return result;
    }

    @Autowired
    private KafkaTemplate kafkaTemplate;

    /**
     * 文章存入草稿/提交审核
     *
     * @param dto
     * @param status 是否为草稿   0草稿   1提交（待审核）
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto, Short status) {
        //1.参数校验
        if (dto == null || StringUtils.isBlank(dto.getTitle()) || StringUtils.isBlank(dto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.参数处理,保存WmNews数据
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto, wmNews);
        //如果是自动(type=-1),则设置为null
        if (dto.getType().intValue() == WemediaConstants.WM_NEWS_TYPE_AUTO.intValue()) {
            wmNews.setType(null);
        }
        //处理图片(去前缀),封装图片,自定义方法imageListToStr()
        String images = imageListToStr(dto.getImages(), webSite);
        wmNews.setImages(images);

        //执行保存或者修改,自定义方法saveNews
        saveNews(wmNews);

        //3.保存 内容中 的图片与素材的关系
        //json转成list集合
        List<Map<String, String>> contents = JSON.parseObject(wmNews.getContent(), List.class);
        //解析文章内容中的图片列表,并且去除前缀,自定义方法parseContentImages
        List<String> materials = parseContentImages(contents);
        //保存关系到文章和素材中间表,自定义方法saveRelativeInfoForContent
        if (materials.size() > 0 && status == WmNews.Status.SUBMIT.getCode()) {
            saveRelativeInfoForContent(materials, wmNews.getId());
        }

        //保存封面中的图片与素材的关系,自定义方法saveRelativeInfoForCover
        if (status == WmNews.Status.SUBMIT.getCode()) {
            saveRelativeInfoForCover(dto, materials, wmNews);
        }
        //4. 发消息(文章id)给admin审核文章(异步)
        if (status == WmNews.Status.SUBMIT.getCode()) {
            Map<String, Integer> map = new HashMap<>();
            map.put(NewsAutoScanConstants.WM_NEWS_ID, wmNews.getId());
            kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC, JSON.toJSONString(map));
        }
        //返回结果
        return ResponseResult.okResult();

    }

    /**
     * 根据id查询文章内容(展示编辑内容)
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult findById(Integer id) {
        //参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //执行查询
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //返回数据
        ResponseResult result = ResponseResult.okResult(wmNews);
        result.setHost(webSite);

        return result;
    }

    /**
     * 根据id删除文章(文章发布不能删除)
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult deleteById(Integer id) {
        //参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //获取数据
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //已发布不能删除(判断发布状态=9和上架状态enable=1)
        if (wmNews.getStatus() == WemediaConstants.WM_NEWS_PUBLISH_STATUS.intValue() && wmNews.getEnable()) {
            CustException.cust("文章已发布,无法删除");
        }
        //删除素材与文章的关系
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                .eq(WmNewsMaterial::getNewsId, wmNews.getId()));
        //删除文章
        removeById(id);

        //*********删除同步索引库***********
        Map<String, Object> map = new HashMap<>();
        map.put("id", wmNews.getArticleId().toString());
        kafkaTemplate.send(ArticleConstants.ARTICL_ES_DELETE_TOPIC, JSON.toJSONString(map));

        return ResponseResult.okResult();
    }

    /**
     * 上架/下架
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //参数校验
        if (dto == null || dto.getId() == null || dto.getEnable() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //查询文章
        WmNews wmNews = getById(dto.getId());
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //未发布不能上下架
        if (wmNews.getStatus() != WemediaConstants.WM_NEWS_PUBLISH_STATUS.intValue()) {
            CustException.cust("文章未发布,不能上下架");
        }
        //设置enable
        if (dto.getEnable() > -1 && dto.getEnable() < 2) {
            update(Wrappers.<WmNews>lambdaUpdate()
                    .eq(WmNews::getId, wmNews.getId())
                    .set(WmNews::getEnable, dto.getEnable()));
        }
        //kafka异步发消息,修改ap_article_config表
        if (wmNews.getArticleId() != null) {
            Map<String, Object> map = new HashMap<>();
            map.put("enable", dto.getEnable());
            map.put("articleId", wmNews.getArticleId());
            kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC, JSON.toJSONString(map));
        }
        //*****同步ES索引库********
        ApArticle apArticle = articleFeign.findArticleById(wmNews.getArticleId());
        if (dto.getEnable() == 1) {
            //上架 --->新增索引库文章
            Map<String, Object> map = new HashMap<>();
            map.put("id", apArticle.getId().toString());
            map.put("publishTime", apArticle.getPublishTime());
            map.put("layout", apArticle.getLayout());
            map.put("images", apArticle.getImages());
            map.put("authorId", apArticle.getAuthorId());
            map.put("title", apArticle.getTitle());
            kafkaTemplate.send(ArticleConstants.ARTICL_ES_SYNC_TOPIC, JSON.toJSONString(map));
        }else{
            //下架 --->删除索引库文章
            Map<String, Object> map = new HashMap<>();
            map.put("id", apArticle.getId().toString());
            kafkaTemplate.send(ArticleConstants.ARTICL_ES_DELETE_TOPIC, JSON.toJSONString(map));
        }

        return ResponseResult.okResult();
    }

    /**
     * 查询需要发布的文章id列表
     *
     * @return
     */
    @Override
    public List<Integer> findRelease() {
        //查询状态为4或为8的数据且发布时间小于当前时间
        List<WmNews> list = list(Wrappers.<WmNews>lambdaQuery()
                .le(WmNews::getPublishTime, new Date())
                .in(WmNews::getStatus, 4, 8)
                .select(WmNews::getId));
        List<Integer> idList = list.stream().map(WmNews::getId)
                .collect(Collectors.toList());
        return idList;
    }

    /**
     * 在admin端展示内容审核的页面(分页查询)
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(NewsAuthDto dto) {
        //1 参数校验
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();
        //2 执行查询
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery();
        //设置条件
        if (StringUtils.isNotBlank(dto.getTitle())) {
            wrapper.like(WmNews::getTitle, dto.getTitle());
        }
        if (dto.getStatus() != null) {
            wrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        wrapper.orderByDesc(WmNews::getCreatedTime);
        //分页查询WmNews
        IPage<WmNews> page = page(new Page<WmNews>(dto.getPage(), dto.getSize()), wrapper);
        List<WmNews> wmNewsList = page.getRecords();

        //3 数据处理
        List<NewsAuthVo> newsAuthVoList = new ArrayList<>();
        for (WmNews wmNews : wmNewsList) {
            NewsAuthVo newsAuthVo = new NewsAuthVo();
            BeanUtils.copyProperties(wmNews, newsAuthVo);
            //获取用户姓名
            WmUser wmUser = wmUserMapper.selectOne(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getId, wmNews.getUserId()));
            if (wmUser != null) {
                newsAuthVo.setAuthorName(wmUser.getName());
                newsAuthVoList.add(newsAuthVo);
            }
        }
        //4 封装返回
        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), page.getTotal(), newsAuthVoList);
        result.setHost(webSite);
        return result;

    }

    /**
     * 在admin端查看内容审核的详情(包含作者)
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult findNewsAuthVo(Integer id) {
        //参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id查询wmNews
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            CustException.cust("数据不存在");
        }
        //数据处理
        NewsAuthVo newsAuthVo = new NewsAuthVo();
        BeanUtils.copyProperties(wmNews, newsAuthVo);
        //添加作者
        WmUser wmUser = wmUserMapper.selectOne(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getId, wmNews.getUserId()));
        if (wmUser != null) {
            newsAuthVo.setAuthorName(wmUser.getName());
        }
        //封装返回
        ResponseResult result = ResponseResult.okResult(newsAuthVo);
        result.setHost(webSite);
        return result;
    }

    /**
     * 内容审核通过/驳回
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult authPassOrFail(NewsAuthDto dto) {
        //参数校验
        if (dto == null || dto.getStatus() == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id查询wmNews
        WmNews wmNews = getById(dto.getId());
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //设置状态status/msg
        wmNews.setStatus(dto.getStatus());
        wmNews.setReason(dto.getMsg());
        //更新表
        updateById(wmNews);
        //封装返回
        return ResponseResult.okResult();
    }

    /**
     * 保存文章中 封面图片 和 素材的关系
     *
     * @param dto       前端参数
     * @param materials 内容中的图片url列表（无前缀）
     * @param wmNews    文章数据
     */
    private void saveRelativeInfoForCover(WmNewsDto dto, List<String> materials, WmNews wmNews) {
        //取出图片集合(有前缀)
        List<String> images = dto.getImages();
        //判断自动(type=-1)时的操作,取图片存数据库中
        if (dto.getType() == WemediaConstants.WM_NEWS_TYPE_AUTO.intValue()) {
            int size = materials.size();
            if (size > 0 && size < 3) {//单图
                images = materials.stream().limit(1).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE.intValue());
            }
            if (size >= 3) {//多图
                images = materials.stream().limit(3).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE.intValue());
            }
            if (size == 0) {//无图
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE.intValue());
            }
            //执行修改
            if (images != null && images.size() > 0) {
                String url = imageListToStr(images, webSite);
                wmNews.setImages(url);
                updateById(wmNews);
            }
        }
        //执行保存关系操作
        if (images != null && images.size() > 0) {
            //处理前缀
            images = images.stream()
                    .map(url -> url.replace(webSite, "").replace(" ", ""))
                    .collect(Collectors.toList());
            saveRelativeInfo(images, wmNews.getId(), WemediaConstants.WM_IMAGE_REFERENCE);
        }
    }

    /**
     * 保存文章内容中的 图片 与素材的关系
     *
     * @param materials
     * @param wmNewsId
     */
    private void saveRelativeInfoForContent(List<String> materials, Integer wmNewsId) {
        saveRelativeInfo(materials, wmNewsId, WemediaConstants.WM_CONTENT_REFERENCE);
    }

    /**
     * 执行保存文章与素材的关系
     *
     * @param materials 图片url列表(无前缀)
     * @param wmNewsId  文章id
     * @param type      0内容引用  1封面引用
     */
    private void saveRelativeInfo(List<String> materials, Integer wmNewsId, Short type) {
        //根据url查询对应的图片id列表
        List<WmMaterial> materialsList = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                .in(WmMaterial::getUrl, materials)
                .eq(WmMaterial::getUserId, WmThreadLocalUtils.getUser().getId()));
        //校验列表
        if (materialsList == null || materialsList.size() == 0) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        Map<String, Integer> matreialMap = materialsList.stream()
                .collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
        List<Integer> materialIds = new ArrayList<>();
        for (String url : materials) {
            Integer id = matreialMap.get(url);
            if (id == null) {
                CustException.cust("图片素材已被删除，请重新上传素材");
            }
            materialIds.add(id);
        }
        //3 执行保存到数据库 wm_news_matreial
        wmNewsMaterialMapper.saveRelations(materialIds, wmNewsId, type);
    }

    /**
     * 解析文章内容中的图片列表,并且去除前缀
     * 目的为了获取materialId
     *
     * @param contents
     * @return
     */
    private List<String> parseContentImages(List<Map<String, String>> contents) {
        return contents.stream()
                //过滤type=image的map集合
                .filter(map -> map.get("type").equals(WemediaConstants.WM_NEWS_TYPE_IMAGE))
                //获取value,即图片全路径
                .map(x -> x.get("value"))
                //去前缀
                .map(url -> url.replace(webSite, "").replace(" ", ""))
                .collect(Collectors.toList());
    }

    /**
     * 保存或修改wmNews
     * 区别:有无id
     *
     * @param wmNews
     */
    private void saveNews(WmNews wmNews) {
        //判断是保存还是修改
        if (wmNews.getId() == null) {
            //保存
            wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
            wmNews.setCreatedTime(new Date());
            wmNews.setSubmitedTime(new Date());
            wmNews.setEnable(true);
            save(wmNews);
        } else {
            //修改
            //***删除文章和素材中间表数据
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId, wmNews.getId()));
            //更新
            wmNews.setSubmitedTime(new Date());
            updateById(wmNews);
        }

    }


    /**
     * 处理图片(去前缀),封装图片
     *
     * @param images
     * @param webSite
     * @return
     */
    private String imageListToStr(List<String> images, String webSite) {
        if (images.size() > 0) {
            return images.stream()
                    .map(url -> url.replace(webSite, "").replace(" ", ""))
                    .collect(Collectors.joining(","));
        }
        return null;
    }
}
